package com.mrx.agent.plugin;

import com.mrx.agent.advice.ProcessBuilderAdvice;
import com.mrx.agent.util.ReflectionUtils;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;

import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

/**
 * @author Mr.X
 * @since 2024-11-05 13:35
 **/
public class XByteBuddyTransformer extends BasePlugin {

    @Override
    public List<AgentBuilder.Transformer> transformers() {
        return List.of(adviceTransformer(), debugTransformer());
    }

    @Override
    public void setArgs(Set<String> args, Class<?> dependencyClass) {
        log("setArgs: " + args);
        ReflectionUtils.invokeMethod("addArgs", args, dependencyClass, Set.class);
    }

    @Override
    public Set<String> dependencies() {
        return Set.of(ProcessBuilderAdvice.class.getName());
    }

    private XTransformer adviceTransformer() {
        var advice = Advice.to(ProcessBuilderAdvice.class).on(isConstructor().and(takesArguments(List.class)));
        return (builder, type) -> {
            log("adviceTransformer: " + type.getName());
            return builder.visit(advice);
        };
    }

    private XTransformer debugTransformer() {
        return (builder, type) -> {
            log("debugTransformer: " + type.getName());
            try (var clazz = builder.make()) {
                Files.write(Path.of("./test/%s.class".formatted(type.getSimpleName())), clazz.getBytes());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return builder;
        };
    }

}
